/*
 * JVMWrapper.cpp  0.4.0 / Nov 14, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "JVMWrapper.h"

// JVMWrapper :: Includes. -----------------------------------------------------

#include "JNIWrapper.h"

#include "com_cute4j_Cute4j.h"

// JVMWrapper :: Public Static Member Functions. -------------------------------

/*!
 * \brief Initializes JVMWrapper class.
 *
 * \param jvm the JNI JavaVM pointer
 *
 * \return JNIEnv version
 */
void JVMWrapper::initialize(JavaVM *jvm)
{
  Q_ASSERT(jvm);
  if (!sm_jvm) {
    if (jvm) {
      sm_jvm = jvm;
      JNIEnv *env;
      jvm->GetEnv((void **)&env, CUTE4J_JNI_VERSION);
      if (env) {
        jclass cls = env->FindClass("com/cute4j/Cute4j");
        if (cls) {
          jfieldID fid = env->GetStaticFieldID(cls, "NATIVE_VERSION", "I");
          if (fid && (env->GetStaticIntField(cls, fid) ==
              com_cute4j_Cute4j_NATIVE_VERSION)) {
            JNIWrapper::initialize(env);
          } else {
            qFatal("Invalid library version! \n\nProgram will exit.");
          }
          env->DeleteLocalRef(cls);
        } else {
          qFatal("Could not find Cute4j class! \n\nProgram will exit.");
        }
      } else {
        qFatal("Null JNIEnv! \n\nProgram will exit. ");
      }
    } else {
      qFatal("Null JVM! \n\nProgram will exit. ");
    }
  }
}

/*!
 * \brief Returns JNIEnv pointer.
 *
 * \return JNIEnv pointer
 */
JNIEnv *JVMWrapper::getEnv()
{
  JNIEnv *env = 0;
  if (sm_jvm) {
    sm_jvm->GetEnv((void **)&env, CUTE4J_JNI_VERSION);
  }
  return env;
}

/*!
 * \brief Exits JVM.
 *
 * \param status the status code
 */
void JVMWrapper::exit(int status)
{
  if (sm_jvm) {
    JNIEnv *env;
    sm_jvm->GetEnv((void **)&env, CUTE4J_JNI_VERSION);
    exitJVM(env, status);
    sm_jvm->DestroyJavaVM();
  }
}

/*!
 * \brief Displays error message and exits JVM.
 *
 * \param status the status code
 */
void JVMWrapper::exitCritical(int status)
{
  if (sm_jvm) {
    JNIEnv *env;
    sm_jvm->GetEnv((void **)&env, CUTE4J_JNI_VERSION);
    if (env && (env->ExceptionCheck())) {
      env->ExceptionDescribe();
      env->ExceptionClear();
    }
    Cute4j::ErrorMessage("Cute4j Internal",
                         "Fatal error occurred. Program will exit. ");
    exitJVM(env, status);
    sm_jvm->DestroyJavaVM();
  }
}

/*!
 * \brief Attaches current thread.
 *
 * \return \c true if succeed
 */
bool JVMWrapper::attachCurrentThread()
{
  JNIEnv *env = 0;
  if (sm_jvm) {
    return (!sm_jvm->AttachCurrentThread((void **)&env, 0));
  }
  return false;
}

/*!
 * \brief Dttaches current thread.
 *
 * \return \c true if succeed
 */
bool JVMWrapper::detachCurrentThread()
{
  if (sm_jvm) {
    return (!sm_jvm->DetachCurrentThread());
  }
  return false;
}

// JVMWrapper :: Private Static Member Function. -------------------------------

void JVMWrapper::exitJVM(JNIEnv *env, int status)
{
  if (env) {
    jclass cls = env->FindClass("java/lang/System");
    if (cls) {
      jmethodID exitMID = env->GetStaticMethodID(cls, "exit", "(I)V");
      if (exitMID) {
        env->CallStaticVoidMethod(cls, exitMID, status);
      }
      env->DeleteLocalRef(cls);
    }
  }
}

// JVMWrapper :: Private Static Data Member. -----------------------------------

JavaVM *JVMWrapper::sm_jvm = 0;
